using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Scintilla.Configuration.SciTE;
using Scintilla.Configuration;
using System.IO;

namespace Ltf.Diffs
{

	public partial class LizardDiff : Control
	{
		private SciTEProperties properties;
		private ScintillaConfig scintillaConfig;

		public event EventHandler LineClick;

		public LizardDiff()
		{
			InitializeComponent();

			//FileInfo exeFile = new FileInfo(Application.ExecutablePath);
			//FileInfo globalConfigFile = new FileInfo(exeFile.Directory.FullName + @"\Configuration\global.properties");
			//if (globalConfigFile.Exists)
			//{
			//  properties = new SciTEProperties();
			//  properties.Load(globalConfigFile);
			//  scintillaConfig = new ScintillaConfig(properties);
			//}

			//string language = properties.GetLanguageFromExtension("cs");
			//sciMainLeft.Configuration = scintillaConfig;
			//sciMainLeft.ConfigurationLanguage = language;
			//language = properties.GetLanguageFromExtension("cs");
			//sciMainRight.Configuration = scintillaConfig;
			//sciMainRight.ConfigurationLanguage = language;

			foreach (ScintillaExtra control in new ScintillaExtra[] { sciMainLeft, sciMainRight, sciSideLeft, sciSideRight })
			{
				control.StartStyling(0, 31);
				control.StyleSetFont(0, "Courier New");
				control.StyleSetSize(0, 8);
				control.SetStyling(0, 0);
			}
			AllReadOnly(false);
			sciSideLeft.ScrollWidth = 1;
			sciSideRight.ScrollWidth = 1;

			sciSideLeft.MarginWidthN(1, 0);
			sciSideRight.MarginWidthN(1, 0);

			sciMainLeft.IsVScrollBar = false;
			sciMainRight.IsVScrollBar = false;

			vsbDocScroller.Minimum = 0;
			vsbDocScroller.Maximum = sciMainLeft.LineCount - 1;

			sciMainLeft.TabWidth = 3;
			sciMainRight.TabWidth = 3;

			//sciMainLeft.ViewWhitespace = Scintilla.Enums.WhiteSpace.VisibleAlways;
			//sciMainRight.ViewWhitespace = Scintilla.Enums.WhiteSpace.VisibleAlways;

			vsbDocScroller.Scroll += new ScrollEventHandler(vsbDocScroller_Scroll);
			sciMainLeft.NativeScintillaEvent += new EventHandler<Scintilla.NativeScintillaEventArgs>(sciMainLeft_NativeScintillaEvent);
			sciMainRight.NativeScintillaEvent += new EventHandler<Scintilla.NativeScintillaEventArgs>(sciMainLeft_NativeScintillaEvent);
			sciSideLeft.NativeScintillaEvent += new EventHandler<Scintilla.NativeScintillaEventArgs>(sciMainLeft_NativeScintillaEvent);
			sciSideRight.NativeScintillaEvent += new EventHandler<Scintilla.NativeScintillaEventArgs>(sciMainLeft_NativeScintillaEvent);

			//			this.MouseUp += new MouseEventHandler(LizardDiff_MouseUp);

			sciMainLeft.MouseUp += new MouseEventHandler(LizardDiff_MouseUp);
			sciSideLeft.MouseUp += new MouseEventHandler(LizardDiff_MouseUp);
			sciMainRight.MouseUp += new MouseEventHandler(LizardDiff_MouseUp);
			sciSideRight.MouseUp += new MouseEventHandler(LizardDiff_MouseUp);

			AllReadOnly(true);

			sciMainLeft.Click += new EventHandler(sciMain_Clink);
			sciMainRight.Click += new EventHandler(sciMain_Clink);
		}

		private void AllReadOnly(bool readOnly)
		{
			sciMainLeft.IsReadOnly = readOnly;
			sciSideLeft.IsReadOnly = readOnly;
			sciMainRight.IsReadOnly = readOnly;
			sciSideRight.IsReadOnly = readOnly;

		}

		public void ShowBlame(string blameFile)
		{
			AllReadOnly(false);

			splitter1.Left = 200;
			sciMainLeft.Width = 200;
			sciSideLeft.Width = 0;
			sciSideLeft.Visible = false;
			Differ differ = new Differ(blameFile);
			ScintillaDiffDocLoader.ShowBlameDocument(sciSideLeft, sciMainLeft, differ.CombinedDocument);
			ScintillaDiffDocLoader.ShowDiffDocument(sciSideRight, sciMainRight, differ.CombinedDocument);
			vsbDocScroller.Maximum = sciMainLeft.LineCount - 1;
			sciMainLeft.IsVScrollBar = false;
			sciSideLeft.IsVScrollBar = false;
			sciMainRight.IsVScrollBar = false;
			sciSideRight.IsVScrollBar = false;
			AllReadOnly(true);
		}

		public void ShowDiffInLine(string fileLeft, string fileRight)
		{
			AllReadOnly(false);

			sciMainRight.Width = sciSideRight.Width = splitter1.Width = 0;
			splitter1.Left = this.Width;
			sciMainLeft.Width = this.Width - sciSideLeft.Width;

			Differ differ = new Differ(fileLeft, fileRight);
			differ.CombinedDocument.RemoveCombinedLines(5);
			ScintillaDiffDocLoader.ShowDiffDocument(sciSideLeft, sciMainLeft, differ.CombinedDocument);
			vsbDocScroller.Maximum = sciMainLeft.LineCount - 1;
			sciMainLeft.IsVScrollBar = false;
			sciSideLeft.IsVScrollBar = false;
			AllReadOnly(true);
		}

		public void ShowDiffSideBySide(string fileLeft, string fileRight)
		{
			AllReadOnly(false);
			Differ differ = new Differ(fileLeft, fileRight);
			ScintillaDiffDocLoader.ShowDiffDocument(sciSideLeft, sciMainLeft, differ.LeftDocument);
			ScintillaDiffDocLoader.ShowDiffDocument(sciSideRight, sciMainRight, differ.RightDocument);
			vsbDocScroller.Maximum = sciMainLeft.LineCount - 1;
			sciSideLeft.IsVScrollBar = false;
			sciMainRight.IsVScrollBar = false;
			sciSideRight.IsVScrollBar = false;
			sciMainLeft.IsVScrollBar = false;
			AllReadOnly(true);
		}


		void sciMain_Clink(object sender, EventArgs e)
		{
			SynchroniseVPositions(sender);
			string line1, line2;
			line1 = line2 = string.Empty;
			if (sender == sciMainLeft)
			{
				line1 = sciMainLeft.GetCurLine();
				int ln = sciMainLeft.LineFromPosition(sciMainLeft.CurrentPos);
				sciMainRight.GotoLine(ln);
				line2 = sciMainRight.GetCurLine();
			}
			else
			{
				line1 = sciMainRight.GetCurLine();
				int ln = sciMainRight.LineFromPosition(sciMainRight.CurrentPos);
				sciMainLeft.GotoLine(ln);
				line2 = sciMainLeft.GetCurLine();
			}

			if (LineClick != null)
				LineClick(this, new LineClickEventArgs(line1, line2));

		}

		void LizardDiff_MouseUp(object sender, MouseEventArgs e)
		{
			if (sender == sciMainRight
				|| sender == sciMainLeft
				|| sender == sciSideLeft
				|| sender == sciSideRight)
			{
				SynchroniseVPositions(sender);
			}
		}

		bool isSyncronising = false;
		void sciMainLeft_NativeScintillaEvent(object sender, Scintilla.NativeScintillaEventArgs e)
		{
			int lParam16 = (int)e.Msg.LParam & 0xFFFF;

			if ((int)e.Msg.LParam != 0xE078 && (int)e.Msg.LParam != 0xE118 && (int)e.Msg.LParam != 0xE0B8)
			{
				if (((int)lParam16 == 0xE1A0 || (int)lParam16 == 0xDA18
					|| (int)lParam16 == 0xE1D0 || (int)lParam16 == 0xD9F8
					|| (int)lParam16 == 0xBF78 || (int)lParam16 == 0xD998) && !isSyncronising)
				{
					object o = null;
					if (e.Msg.HWnd == sciMainLeft.Handle)
						o = sciMainLeft;
					else if (e.Msg.HWnd == sciMainRight.Handle)
						o = sciMainRight;
					else if (e.Msg.HWnd == sciSideLeft.Handle)
						o = sciSideLeft;
					else if (e.Msg.HWnd == sciSideRight.Handle)
						o = sciSideRight;
					SynchroniseVPositions(o);
				}
				else
				{
					//				Console.Write("Event {0:x8} - {1:x8} , {2:x8}\r\n", e.Msg.Msg, (int)e.Msg.LParam, (int)e.Msg.WParam);
				}
			}
		}

		void SynchroniseVPositions(object sender)
		{
			isSyncronising = true;
			Scintilla.ScintillaControl control = (Scintilla.ScintillaControl)sender;
			int pos = control.PositionFromPoint(0, 0);
			int newline = control.LineFromPosition(pos);
			int oldline = 0;
			if (control == sciMainLeft)
			{
				pos = sciSideLeft.PositionFromPoint(0, 0);
				oldline = sciSideLeft.LineFromPosition(pos);
			}
			else
			{
				pos = sciMainLeft.PositionFromPoint(0, 0);
				oldline = sciMainLeft.LineFromPosition(pos);
			}
			int lines = newline - oldline;
			if (control != sciSideLeft)
				sciSideLeft.LineScroll(0, lines);
			if (control != sciSideRight)
				sciSideRight.LineScroll(0, lines);
			if (control != sciMainLeft)
				sciMainLeft.LineScroll(0, lines);
			if (control != sciMainRight)
				sciMainRight.LineScroll(0, lines);
			isSyncronising = false;
		}

		void vsbDocScroller_Scroll(object sender, ScrollEventArgs e)
		{
			int old = e.OldValue;
			int lines = e.NewValue - old;
			sciSideLeft.LineScroll(0, lines);
			sciSideRight.LineScroll(0, lines);
			sciMainLeft.LineScroll(0, lines);
			sciMainRight.LineScroll(0, lines);
		}
	}

}